using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace FallenValkyrie
{
    class Player : Character
    {
        #region Load Content
        
        // Animation
        public Animation Idle, Run, Atk, HeavyAtk, JumpUp, JumpDown, CastSkill, Fireball, GetHit;

        //public bool AtkAnimation;
        //public string AtkDirection, SightDirection;

        // Sound Effect
        SoundEffect AtkSE;
        SoundEffectInstance AtkSEIns;
        public SoundEffect AtkHitSE;
        public SoundEffectInstance ATkHitSEIns;

        // Hit box position and size
        //public int Atk_xPos, Atk_yPos, Atk_xSize, Atk_ySize;
        
        public void Load(ContentManager content)
        {
            // Animation
            Idle = new Animation(content, "Characters/Player/idle", 250, 146, 8, 20);
            Run = new Animation(content, "Characters/Player/run", 250, 146, 8, 30);
            Atk = new Animation(content, "Characters/Player/atk3", 250, 146, 2, 8);
            CastSkill = new Animation(content, "Characters/Player/castSkill", 250, 146, 8, 10);
            HeavyAtk = new Animation(content, "Characters/Player/heavyAtk", 250, 146, 5, 10);
            JumpUp = new Animation(content, "Characters/Player/jump", 160, 104, 3, 30);
            JumpDown = new Animation(content, "Characters/Player/jump", 160, 106, 5, 30);
            Fireball = new Animation(content, "Characters/Player/Fireballs", 96, 96, 8, 20);
            GetHit = new Animation(content, "Characters/Player/getHit", 250, 146, 1, 1);
            
            Idle.EnableRepeating();
            Run.EnableRepeating();
            Atk.EnableRepeating();
            HeavyAtk.EnableRepeating();
            CastSkill.EnableRepeating();
            Fireball.EnableRepeating();
            JumpUp.EnableRepeating();
            JumpDown.SetStartingFrame(4);

            // Sound Effect
            AtkHitSE = content.Load<SoundEffect>("Characters/Player/Sound/AtkHit");
            ATkHitSEIns = AtkHitSE.CreateInstance();
            AtkSE = content.Load<SoundEffect>("Characters/Player/Sound/Atk");
            AtkSEIns = AtkSE.CreateInstance();
        }
        #endregion

        #region Update
        public void Update(GameTime gameTime)
        {
            UpdateAllStates(gameTime);
            SightChecking();
            //Editor();
        }
        #endregion

        KeyboardState keys;

        public void Editor()
        {
            keys = Keyboard.GetState();

            if (keys.IsKeyDown(Keys.Q))
                skillPosition.X--;
            else if (keys.IsKeyDown(Keys.W))
                skillPosition.Y++;

            Console.WriteLine("skillPosition.X = " + skillPosition.X + " skillPosition.Y = " + skillPosition.Y);
        }

        private void SightChecking()
        {
            if (spriteEffects == SpriteEffects.None)
                SightDirection = "left";
            else
                SightDirection = "right";
        }

        #region Update Control

        //KeyboardState mPreviousKeyboardState;
        public SpriteEffects spriteEffects = SpriteEffects.FlipHorizontally;
        public Vector2 feetPosition = new Vector2(0, 618);

        Vector2 skillPosition = new Vector2(0, 55);
        
        //Vector2 mSpeed = Vector2.Zero;
       //Vector2 mDirection = Vector2.Zero;
        //Vector2 mStartingPosition = Vector2.Zero;

        int CHARACTER_SPEED = 50;
        int MOVE_LEFT = -5;
        int MOVE_RIGHT = 5;
        int MOVE_UP = -5;
        int MOVE_DOWN = 5;

        enum State
        {
            Idle,
            Run_to_Left,
            Run_to_Right,
            Jump_Up,
            Jump_Down,
            Attack,
            Heavy_Attacking,
            Cast_Skill,
            Fireball,
            Get_Hit
        }
        public float getHitTimeDelay = 0;
        public bool getHitState;
        State PlayerState = State.Idle;
        State SkillState;
        public string Input;

        bool hasJumped;

        public void UpdateCutSceneMovement()
        {
            if (Input == "run to left")
                PlayerState = State.Run_to_Left;
            else if (Input == "run to right")
                PlayerState = State.Run_to_Right;
        }

        public void UpdatePlayerInput(KeyboardState aCurrentKeyboardState, KeyboardState mPreviousKeyboardState)
        {
            if (aCurrentKeyboardState.IsKeyDown(Keys.Left) && !aCurrentKeyboardState.IsKeyDown(Keys.Right))
                Input = "run to left";
            else if (aCurrentKeyboardState.IsKeyDown(Keys.Right) && !aCurrentKeyboardState.IsKeyDown(Keys.Left))
                Input = "run to right";
            else
                Input = "idle";

            if (aCurrentKeyboardState.IsKeyDown(Keys.Z) && mPreviousKeyboardState.IsKeyUp(Keys.Z))
                Input = "attack";
            else if (aCurrentKeyboardState.IsKeyDown(Keys.X) && mPreviousKeyboardState.IsKeyUp(Keys.X))
                Input = "heavy attack";
            else if (aCurrentKeyboardState.IsKeyDown(Keys.Up) && mPreviousKeyboardState.IsKeyUp(Keys.Up))
                Input = "jump";

            if (aCurrentKeyboardState.IsKeyDown(Keys.D1) && mPreviousKeyboardState.IsKeyUp(Keys.D1))
                Input = "cast skill";
        }

        private void UpdateAllStates(GameTime gameTime)
        {
            feetPosition += mDirection * mSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;

            UpdateMovement(gameTime);
            UpdateAttack(gameTime);
            UpdateSkill(gameTime);
            UpdateJump(gameTime);
            UpdateGetHit(gameTime);
        }

        private void UpdateMovement(GameTime gameTime)
        {
            if (PlayerState == State.Idle)
            {
                mSpeed = Vector2.Zero;
                mDirection = Vector2.Zero;

                Idle.Update(gameTime);

                if (Input == "run to left")
                    PlayerState = State.Run_to_Left;
               else if (Input == "run to right")
                    PlayerState = State.Run_to_Right;
            }

            if (PlayerState == State.Run_to_Left)
            {
                Run.Update(gameTime);

                spriteEffects = SpriteEffects.None;
                mSpeed.X = CHARACTER_SPEED;
                mDirection.X = MOVE_LEFT;
                
                if (Input == "idle")
                    PlayerState = State.Idle;
            }

            if (PlayerState == State.Run_to_Right)
            {
                Run.Update(gameTime);

                spriteEffects = SpriteEffects.FlipHorizontally;
                mSpeed.X = CHARACTER_SPEED;
                mDirection.X = MOVE_RIGHT;

                if (Input == "idle")
                    PlayerState = State.Idle;
            }

            if (Input == "attack")
                PlayerState = State.Attack;
            else if (Input == "heavy attack")
                PlayerState = State.Heavy_Attacking;
            else if (Input == "cast skill")
                PlayerState = State.Cast_Skill;

            if (getHitState)
                PlayerState = State.Get_Hit;
            
        }

        public bool EndNormalAttack;

        private void UpdateAttack(GameTime gameTime)
        {
            if (PlayerState == State.Attack)
            {
                Atk.Update(gameTime);
                DmgAnimation = true;
                //EndNormalAttack = true;

                if (AtkSEIns.State != SoundState.Playing)
                    AtkSEIns.Play();
                
                
                if (spriteEffects == SpriteEffects.FlipHorizontally)
                {
                    mSpeed.X = CHARACTER_SPEED;
                    mDirection.X = MOVE_RIGHT;
                    AtkDirection = "right";
                }
                else
                {
                    mSpeed.X = CHARACTER_SPEED;
                    mDirection.X = MOVE_LEFT;
                    AtkDirection = "left";
                }
                
                timeDelay += (float)gameTime.ElapsedGameTime.TotalSeconds;

                if (timeDelay > 0.25)
                {
                    if (hasJumped == true)
                    {
                        PlayerState = State.Jump_Down;
                    }
                    else
                        PlayerState = State.Idle;

                    timeDelay = 0;
                    DmgAnimation = false;
                    EndNormalAttack = false;
                }
            }
            
            if (PlayerState == State.Heavy_Attacking)
            {
                HeavyAtk.Update(gameTime);
                DmgAnimation = true;

                if (spriteEffects == SpriteEffects.FlipHorizontally)
                {
                    mSpeed.X = CHARACTER_SPEED;
                    mDirection.X = MOVE_RIGHT;
                    AtkDirection = "right";
                }
                else
                {
                    mSpeed.X = CHARACTER_SPEED;
                    mDirection.X = MOVE_LEFT;
                    AtkDirection = "left";
                }

                if (HeavyAtk.EndAnimation)
                {
                    if (hasJumped == true)
                    {
                        PlayerState = State.Jump_Down;
                    }
                    else
                        PlayerState = State.Idle;

                    HeavyAtk.EndAnimation = false;
                    DmgAnimation = false;
                }
            }
            
        }

        bool initialize = true;

        private void UpdateSkill(GameTime gameTime)
        {
            if (PlayerState == State.Cast_Skill)
            {
                CastSkill.Update(gameTime);

                if (spriteEffects == SpriteEffects.FlipHorizontally)
                {
                    AtkDirection = "right";
                }
                else
                {
                    AtkDirection = "left";
                }

                if (CastSkill.EndAnimation)
                {
                    SkillState = State.Fireball;
                    CastSkill.EndAnimation = false;

                    if (hasJumped == true)
                    {
                        PlayerState = State.Jump_Down;
                    }
                    else
                        PlayerState = State.Idle;
                }
            }

            if (SkillState == State.Fireball)
            {
                Fireball.Update(gameTime);

                if (spriteEffects == SpriteEffects.FlipHorizontally)
                {
                    if (initialize)
                    {
                        skillPosition.X = 135;
                        initialize = false;
                    }

                    skillPosition.X += 2;
                }
                else
                {
                    if (initialize)
                    {
                        skillPosition.X = 19;
                        initialize = false;
                    }
                    skillPosition.X -= 2;
                }

                DmgAnimation = true;

                if (skillPosition.X == 199 || skillPosition.X == -45)
                {
                    SkillState = State.Idle;
                    skillPosition.X = 135;
                    DmgAnimation = false;
                    initialize = true;
                    EndNormalAttack = false;
                }
            }
        }
       
        public void UpdateGetHit(GameTime gameTime)
        {
            if (PlayerState == State.Get_Hit) 
            {
                GetHit.Update(gameTime);

                timeDelay += (float)gameTime.ElapsedGameTime.TotalSeconds;

                if (spriteEffects == SpriteEffects.FlipHorizontally) {
                    mSpeed.X = 0;
                    mDirection.X = 1;
                } else {
                    mSpeed.X = 0;
                    mDirection.X = -1;
                }

                if (timeDelay > 1f) {
                    if (hasJumped == true)
                    {
                        PlayerState = State.Jump_Down;
                    }
                    else
                        PlayerState = State.Idle;
  
                    getHitState = false;
                    timeDelay = 0;
                }
            }
        }

        private void UpdateJump(GameTime gameTime)
        { 
            if (PlayerState == State.Idle || PlayerState == State.Run_to_Left || PlayerState == State.Run_to_Right)
            {
                if (Input == "jump")
                {
                    Jump();
                    hasJumped = true;
                }
            }

            if (PlayerState == State.Jump_Up)
            {
                JumpUp.Update(gameTime);
                //Console.WriteLine(feetPosition.Y);
                if (mStartingPosition.Y - feetPosition.Y > 300)
                    PlayerState = State.Jump_Down;
            }

            if (PlayerState == State.Jump_Down)
            {
                mDirection.Y = MOVE_DOWN;

                if (feetPosition.Y > 618)
                {
                    feetPosition.Y = 618;

                    JumpDown.Update(gameTime);

                    timeDelay += (float)gameTime.ElapsedGameTime.TotalSeconds;

                    if (timeDelay > 0.15)
                    {
                        PlayerState = State.Idle;
                        timeDelay = 0;
                        mDirection = Vector2.Zero;

                        hasJumped = false;
                    }
                }
            }
        }

        private void Jump()
        {
            if (PlayerState != State.Jump_Up)
            {
                PlayerState = State.Jump_Up;
                mStartingPosition = feetPosition;
                mDirection.Y = MOVE_UP;
                mSpeed = new Vector2(50, CHARACTER_SPEED);
            }
        }
        #endregion

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Begin(SpriteSortMode.Texture, BlendState.Additive);
            if (SkillState == State.Fireball)
                Fireball.Draw(spriteBatch, feetPosition + skillPosition, spriteEffects, (float)MathHelper.ToRadians(0), 1.0f);
            spriteBatch.End();

            spriteBatch.Begin();
            if (PlayerState == State.Idle)
                Idle.Draw(spriteBatch, feetPosition, spriteEffects, (float)MathHelper.ToRadians(0),1.0f);
            else if (PlayerState == State.Run_to_Left || PlayerState == State.Run_to_Right)
                Run.Draw(spriteBatch, feetPosition, spriteEffects, (float)MathHelper.ToRadians(0),1.0f);

            if (PlayerState == State.Attack)
                Atk.Draw(spriteBatch, feetPosition, spriteEffects, (float)MathHelper.ToRadians(0), 1.0f);
            else if (PlayerState == State.Heavy_Attacking)
                HeavyAtk.Draw(spriteBatch, feetPosition, spriteEffects, (float)MathHelper.ToRadians(0), 1.0f);
            
            if (PlayerState == State.Cast_Skill)
                CastSkill.Draw(spriteBatch, feetPosition, spriteEffects, (float)MathHelper.ToRadians(0), 1.0f);

            if (PlayerState == State.Jump_Up)
                JumpUp.Draw(spriteBatch, feetPosition, spriteEffects, (float)MathHelper.ToRadians(0), 1.0f);
            else if (PlayerState == State.Jump_Down)
                JumpDown.Draw(spriteBatch, feetPosition, spriteEffects, (float)MathHelper.ToRadians(0), 1.0f);

            if (PlayerState == State.Get_Hit)
                GetHit.Draw(spriteBatch, feetPosition, spriteEffects, (float)MathHelper.ToRadians(0), 1.0f);
            spriteBatch.End();
        }
    }
}
